package com.mf.service.impl.basic;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mf.emuns.basic.EnumPermType;
import com.mf.entity.dto.basic.DtoPermission;
import com.mf.entity.req.basic.search.SearchReqPermission;
import com.mf.entity.vo.basic.voPublic.VoPublicKV;
import com.mf.exception.GraceException;
import com.mf.mapper.basic.MapperPermission;
import com.mf.mapper.basic.MapperRolePermission;
import com.mf.service.basic.ServicePermission;
import com.mf.service.basic.ServiceRolePermission;
import com.mf.utils.UtilEnum;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;


@Service
public class ImplServicePermission extends ServiceImpl<MapperPermission, DtoPermission> implements ServicePermission {

    @Resource
    private ServiceRolePermission serviceRolePermission;

    @Resource
    private MapperPermission mapperPermission;

    @Resource
    private MapperRolePermission mapperRolePermission;


    /**
     * 参数查询条件
     */
    @Override
    public LambdaQueryWrapper<DtoPermission> fillParams(SearchReqPermission params) {
        final LambdaQueryWrapper<DtoPermission> wrapper = loadQw();
        wrapper.orderByDesc(DtoPermission::getId);
        if (StringUtils.isNotBlank(params.getKey())) {
            wrapper.and(w -> {
                w.like(DtoPermission::getPermName, params.getKey())
                        .or()
                        .like(DtoPermission::getDescription, params.getKey());
            });
        }

        wrapper.in(ObjectUtils.isNotEmpty(params.getType()), DtoPermission::getPermType, params.getType());
        return wrapper;
    }


    /**
     * 根据角色id查询绑定的权限
     */
    @Override
    public List<DtoPermission> findByRoleId(Integer roleId) {
        List<DtoPermission> permissionList = mapperPermission.findByNoRoleId(roleId);
        if (permissionList.isEmpty()) {
            return permissionList;
        }
        // 已绑定的id
        Set<Integer> boundIds = permissionList.stream().map(DtoPermission::getId).collect(Collectors.toSet());

        // 所有权限
        List<DtoPermission> list = list();
        // 根据父级id进行分组
        return buildBoundDtoPermissions(boundIds, list);
    }

    private List<DtoPermission> buildBoundDtoPermissions(Set<Integer> boundIds, List<DtoPermission> list) {
        Map<Integer, List<DtoPermission>> parentMap =
                list.stream().collect(Collectors.groupingBy(DtoPermission::getPid));
        List<DtoPermission> res = new ArrayList<>();
        for (DtoPermission dtoPermission : list) {
            if (!isFullBound(dtoPermission.getId(), boundIds, parentMap)) {
                res.add(dtoPermission);
            }
        }
        return res;
    }

    /**
     * 根据角色id查询待绑定权限
     */
    @Override
    public List<DtoPermission> findByNoRoleId(Integer roleId) {
        List<DtoPermission> permissionList = mapperPermission.findByRoleId(roleId);
        // 所有的权限
        List<DtoPermission> list = list();
        if (permissionList.isEmpty()) {
            return list;
        }

        // 已绑定的id
        Set<Integer> boundIds = permissionList.stream().map(DtoPermission::getId).collect(Collectors.toSet());

        // 按照父级进行分组
        return buildBoundDtoPermissions(boundIds, list);
    }

    /**
     * 验证子集是否已经全部绑定
     */
    private boolean isFullBound(Integer id, Set<Integer> boundIds, Map<Integer, List<DtoPermission>> parentMap) {
        // 获取对应id下面的子集
        List<DtoPermission> children = parentMap.getOrDefault(id, Collections.emptyList());

        // 如果没有子数据 如果已绑定那么直接返回 true
        if (children.isEmpty()) {
            return boundIds.contains(id);
        }
        return children.stream().allMatch(son -> isFullBound(son.getId(), boundIds, parentMap));
    }

    /**
     * 复制权限码
     */
    @Override
    @Transactional
    public void copy(Integer id) {
        DtoPermission dtoPermission = findCheckById(id, true);
        List<DtoPermission> permissionList = listByPid(id);

        List<DtoPermission> newPermissionList = new ArrayList<>();
        final String COPY = "copy_";
        dtoPermission.setId(null);
        dtoPermission.setPermName(COPY + dtoPermission.getPermName());

        // 新增的权限
        save(dtoPermission);

        for (DtoPermission permission : permissionList) {
            permission.setId(null);
            permission.setPid(dtoPermission.getId());
            permission.setPermName(COPY + permission.getPermName());
        }
        saveBatch(permissionList);
    }

    /**
     * 修改权限
     */
    @Override
    @Transactional
    public void permissionUpdateById(DtoPermission dtoPermission) {
        DtoPermission dtoPermission1 = findCheckById(dtoPermission.getId(), true);
        String oldName = dtoPermission1.getPermName();
        String newName = dtoPermission.getPermName();
        // 如果权限码被修改，同步更新子集的前缀
        if (!oldName.equals(newName)) {
            List<DtoPermission> permissionList = listByPid(dtoPermission.getId());
            for (DtoPermission permission : permissionList) {
                // 有添加
                String[] permNames = permission.getPermName().split(":");
                if (permNames.length > 1 && permNames[0].equals(oldName)) {
                    permission.setPermName(newName + ":" + permNames[1]);
                }
            }
            updateBatchById(permissionList);
        }
        updateById(dtoPermission);
    }

    /**
     * 删除
     */
    @Override
    public void deleteById(Integer id) {
        GraceException.display(serviceRolePermission.countByPermissionId(id) > 0, "当前权限有角色不可删除");
        GraceException.display(countByPid(id) > 0, "当前权限有子节点不可删除");
        removeById(id);
    }

    /**
     * 查询子节点数量
     */
    private long countByPid(Integer id) {
        LambdaQueryWrapper<DtoPermission> wrapper = loadQw();
        wrapper.eq(DtoPermission::getPid, id);
        return count(wrapper);
    }

    /**
     * 查询子节点
     */
    private List<DtoPermission> listByPid(Integer id) {
        LambdaQueryWrapper<DtoPermission> wrapper = loadQw();
        wrapper.eq(DtoPermission::getPid, id);
        return list(wrapper);
    }

    /**
     * 根据角色Id集合查询权限
     */
    @Override
    public List<String> listByRoleId(List<Integer> roleIds) {
        return mapperRolePermission.listByRoleId(roleIds);
    }

    /**
     * 根据类型查询权限码
     */
    @Override
    public List<VoPublicKV> findByType(List<String> type) {
        LambdaQueryWrapper<DtoPermission> wrapper = loadQw();
        if (!type.isEmpty()) {
            for (String s : type) {
                UtilEnum.existsInEnum(EnumPermType.class, s);
            }
            wrapper.in(DtoPermission::getPermType, type);
        }

        return list(wrapper).stream().map(dtoPermission -> VoPublicKV.builder()
                .label(dtoPermission.getDescription())
                .value(dtoPermission.getPermName())
                .build()).toList();
    }

}